home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / vid_sunxil.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  30KB  |  1,289 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // vid_sunxil.c -- uses X to setup windows and XIL to copy images (scaled as needed) 
  21. //            to screen
  22.  
  23. #define _BSD
  24. #define BYTE_DEFINED 1
  25.  
  26. #include <sys/time.h>
  27. #include <sys/types.h>
  28. #include <errno.h>
  29. #include <thread.h>
  30. #include <unistd.h>
  31. #include <signal.h>
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <sys/ipc.h>
  36. #include <sys/shm.h>
  37. #include <X11/Xlib.h>
  38. #include <X11/Xutil.h>
  39. #include <X11/Xatom.h>
  40. #include <X11/keysym.h>
  41. #include <xil/xil.h>
  42.  
  43. #include "quakedef.h"
  44. #include "d_local.h"
  45.  
  46. #define MIN_WIDTH 320
  47. #define MIN_HEIGHT 200
  48.  
  49. cvar_t        _windowed_mouse = {"_windowed_mouse","0", true};
  50. cvar_t        m_filter = {"m_filter","0", true};
  51. float old_windowed_mouse;
  52.  
  53. // The following X property format is defined in Motif 1.1's
  54. // Xm/MwmUtils.h, but QUAKE should not depend on that header
  55. // file. Note: Motif 1.2 expanded this structure with
  56. // uninteresting fields (to QUAKE) so just stick with the
  57. // smaller Motif 1.1 structure.
  58.  
  59. #define MWM_HINTS_DECORATIONS   2
  60. typedef struct
  61. {
  62.     long flags;
  63.     long functions;
  64.     long decorations;
  65.     long input_mode;
  66. } MotifWmHints;
  67.  
  68. #define MAX_COLUMN_SIZE    11
  69.  
  70. #define MAX_MODEDESCS    (MAX_COLUMN_SIZE*3)
  71.  
  72. typedef struct
  73. {
  74.     int        modenum;
  75.     int        iscur;
  76.     char    desc[256];
  77. } modedesc_t;
  78.  
  79. extern void M_Menu_Options_f (void);
  80. extern void M_Print (int cx, int cy, char *str);
  81. extern void M_PrintWhite (int cx, int cy, char *str);
  82. extern void M_DrawCharacter (int cx, int line, int num);
  83. extern void M_DrawTransPic (int x, int y, qpic_t *pic);
  84. extern void M_DrawPic (int x, int y, qpic_t *pic);
  85.  
  86. extern int sb_updates;
  87.  
  88. qboolean        mouse_avail;
  89. int             mouse_buttons=3;
  90. int             mouse_oldbuttonstate;
  91. int             mouse_buttonstate;
  92. float   mouse_x, mouse_y;
  93. float   old_mouse_x, old_mouse_y;
  94. int p_mouse_x;
  95. int p_mouse_y;
  96.  
  97. typedef struct
  98. {
  99.     int input;
  100.     int output;
  101. } keymap_t;
  102.  
  103. viddef_t vid; // global video state
  104. unsigned short       d_8to16table[256];
  105.  
  106. int        num_shades=32;
  107.  
  108. int    d_con_indirect = 0;
  109.  
  110. int        vid_buffersize;
  111.  
  112. #define STD_EVENT_MASK \
  113. ( \
  114.     StructureNotifyMask | \
  115.     KeyPressMask | \
  116.     KeyReleaseMask | \
  117.     ButtonPressMask | \
  118.     ButtonReleaseMask | \
  119.     ExposureMask | \
  120.     PointerMotionMask | \
  121.     FocusChangeMask \
  122. )
  123.  
  124. int        VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar;
  125. byte    *VGA_pagebase;
  126.  
  127. qboolean            x_fullscreen = true;
  128. Display                *x_disp = NULL;
  129. int                x_screen, x_screen_width, x_screen_height;
  130. int                x_center_width, x_center_height;
  131. int                x_std_event_mask = STD_EVENT_MASK;
  132. Window                x_win, x_root_win;
  133. qboolean            x_focus = true;
  134. int                global_dx, global_dy;
  135.  
  136.  
  137. static Colormap            x_cmap;
  138. static GC            x_gc;
  139. static Visual            *x_vis;
  140. static XVisualInfo        *x_visinfo;
  141. static Atom            aHints = NULL;
  142. static Atom            aWMDelete = NULL;
  143.  
  144. static qboolean            oktodraw = false;
  145. static qboolean            X11_active = false;
  146.  
  147.  
  148. static int verbose=1;
  149.  
  150. static byte current_palette[768];
  151.  
  152. cvar_t pixel_multiply = {"pixel_multiply", "2", true};
  153. int current_pixel_multiply = 2;
  154.  
  155. #define PM(a) (int)((current_pixel_multiply)?((a)*current_pixel_multiply):(a))
  156. #define MP(a) (int)((current_pixel_multiply)?((a)/current_pixel_multiply):(a))
  157.  
  158. static int                 render_pipeline[2];
  159. static XilSystemState             state;
  160. static XilImage                display_image  = NULL;
  161. static XilImage                quake_image  = NULL;
  162. static int                use_mt = 0;
  163. static int                count_frames = 0;
  164.  
  165. /*
  166. ================
  167. D_BeginDirectRect
  168. ================
  169. */
  170. void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
  171. {
  172. // direct drawing of the "accessing disk" icon isn't supported under Nextstep
  173. }
  174.  
  175.  
  176. /*
  177. ================
  178. D_EndDirectRect
  179. ================
  180. */
  181. void D_EndDirectRect (int x, int y, int width, int height)
  182. {
  183. // direct drawing of the "accessing disk" icon isnt supported under Nextstep
  184. }
  185.  
  186.  
  187. /*
  188. =================
  189. VID_Gamma_f
  190.  
  191. Keybinding command
  192. =================
  193. */
  194.  
  195. byte vid_gamma[256];
  196.  
  197. void VID_Gamma_f (void)
  198. {
  199.  
  200.     float    g, f, inf;
  201.     int        i;
  202.  
  203.     if (Cmd_Argc () == 2) {
  204.         g = Q_atof (Cmd_Argv(1));
  205.  
  206.         for (i=0 ; i<255 ; i++)    {
  207.             f = pow ((i+1)/256.0, g);
  208.             inf = f*255 + 0.5;
  209.             if (inf < 0)
  210.                 inf = 0;
  211.             if (inf > 255)
  212.                 inf = 255;
  213.             vid_gamma[i] = inf;
  214.         }
  215.  
  216.         VID_SetPalette (current_palette);
  217.  
  218.         vid.recalc_refdef = 1;                // force a surface cache flush
  219.     }
  220.  
  221. }
  222.  
  223. qboolean CheckPixelMultiply (void)
  224. {
  225.     int m;
  226.     int w, h;
  227.     XWindowAttributes wattr;   
  228.     XWindowChanges chg;
  229.     unsigned int value_mask;
  230.     int old_pixel;
  231.  
  232.     if ((m = (int)pixel_multiply.value) != current_pixel_multiply) {
  233.         if (m < 1)
  234.             m = 1;
  235.         if (m > 4)
  236.             m = 4;
  237.  
  238.         old_pixel = current_pixel_multiply;
  239.         current_pixel_multiply = m;
  240.         Cvar_SetValue("pixel_multiply", m);
  241.         
  242.         if(XGetWindowAttributes(x_disp, x_win, & wattr) == 0)
  243.             return true; // ???
  244.  
  245.         memset(&chg, 0, sizeof(chg));
  246.         chg.width = wattr.width/old_pixel * current_pixel_multiply;
  247.         chg.height = wattr.height/old_pixel * current_pixel_multiply;
  248.  
  249.         if (chg.width < MIN_WIDTH*current_pixel_multiply)
  250.             chg.width = MIN_WIDTH*current_pixel_multiply;
  251.         if (chg.height < MIN_HEIGHT*current_pixel_multiply)
  252.             chg.height = MIN_HEIGHT*current_pixel_multiply;
  253.  
  254.         XConfigureWindow(x_disp, x_win, CWWidth | CWHeight, &chg);
  255.  
  256.         vid.width = MP(wattr.width) & ~3;
  257.         vid.height = MP(wattr.height);
  258.  
  259.         if (vid.width < 320) 
  260.             vid.width = 320;
  261.         if (vid.height < 200)
  262.             vid.height = 200;
  263.         VID_ResetFramebuffer();
  264.  
  265.         return true;
  266.     }
  267.     return false;
  268. }
  269.  
  270. // ========================================================================
  271. // Tragic death handler
  272. // ========================================================================
  273.  
  274. void TragicDeath(int signal_num)
  275. {
  276.     //XAutoRepeatOn(x_disp);
  277.     XCloseDisplay(x_disp);
  278.     Sys_Error("This death brought to you by the number %d\n", signal_num);
  279. }
  280.  
  281. // ========================================================================
  282. // makes a null cursor
  283. // ========================================================================
  284.  
  285. static Cursor CreateNullCursor(Display *display, Window root)
  286. {
  287.     Pixmap cursormask; 
  288.     XGCValues xgc;
  289.     GC gc;
  290.     XColor dummycolour;
  291.     Cursor cursor;
  292.  
  293.     cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
  294.     xgc.function = GXclear;
  295.     gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
  296.     XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
  297.     dummycolour.pixel = 0;
  298.     dummycolour.red = 0;
  299.     dummycolour.flags = 04;
  300.     cursor = XCreatePixmapCursor(display, cursormask, cursormask,
  301.                      &dummycolour,&dummycolour, 0,0);
  302.     XFreePixmap(display,cursormask);
  303.     XFreeGC(display,gc);
  304.     return cursor;
  305. }
  306.  
  307.  
  308. void VID_MenuDraw( void )
  309. {
  310.     qpic_t        *p;
  311.     char        *ptr;
  312.     int            i, j, column, row, dup;
  313.     char        temp[100];
  314.  
  315.     p = Draw_CachePic ("gfx/vidmodes.lmp");
  316.     M_DrawPic ( (320-p->width)/2, 4, p);
  317.     M_Print (4*8, 36 + MAX_COLUMN_SIZE * 8 + 8, "Video mode switching unavailable");
  318.     M_Print (9*8, 36 + MAX_COLUMN_SIZE * 8 + 8*6, "Press any key...");
  319. }
  320.  
  321. void VID_MenuKey( int key ) { M_Menu_Options_f (); }
  322.  
  323. // Called at startup to set up translation tables, takes 256 8 bit RGB values
  324. // the palette data will go away after the call, so it must be copied off if
  325. // the video driver will need it again
  326.  
  327. byte    surfcache[1024*1024];
  328.  
  329. //
  330. // VID_SetWindowTitle - set the window and icon titles
  331. //
  332.  
  333. void VID_SetWindowTitle( Window win, char *pszName )
  334. {
  335.     XTextProperty    textprop;
  336.     XWMHints        *wmHints;
  337.  
  338.     // Setup ICCCM properties
  339.     textprop.value = (unsigned char *)pszName;
  340.     textprop.encoding = XA_STRING;
  341.     textprop.format = 8;
  342.     textprop.nitems = strlen(pszName);
  343.     wmHints = XAllocWMHints();
  344.     wmHints->initial_state = NormalState;
  345.     wmHints->flags = StateHint;
  346.     XSetWMProperties( x_disp, win, &textprop, &textprop,
  347.                       // Only put WM_COMMAND property on first window.
  348.                       com_argv, com_argc, NULL, NULL, NULL );
  349.     XFree( wmHints );
  350.  
  351.     aWMDelete = XInternAtom( x_disp, "WM_DELETE_WINDOW", False );
  352.     XSetWMProtocols( x_disp, win, &aWMDelete, 1 );
  353. }
  354.  
  355. //
  356. // VID_FullScreen - open the window in full screen mode
  357. //
  358.  
  359. qboolean VID_FullScreen( Window win )
  360. {
  361.     MotifWmHints    hints;
  362.     XWindowChanges  changes;
  363.  
  364.     aHints = XInternAtom( x_disp, "_MOTIF_WM_HINTS", 0 );
  365.     if (aHints == None) {
  366.         Con_Printf( "Could not intern X atom for _MOTIF_WM_HINTS." );
  367.         return( false );
  368.     }
  369.  
  370.     hints.flags = MWM_HINTS_DECORATIONS;
  371.     hints.decorations = 0; // Absolutely no decorations.
  372.     XChangeProperty( x_disp, win, aHints, aHints, 32, PropModeReplace, (unsigned char *)&hints, 4 );
  373.  
  374.     changes.x = 0;
  375.     changes.y = 0;
  376.     changes.width = x_screen_width;
  377.     changes.height = x_screen_height;
  378.     changes.stack_mode = TopIf;
  379.     XConfigureWindow( x_disp, win, CWX | CWY | CWWidth | CWHeight | CWStackMode, &changes);
  380.     return( true );
  381. }
  382.  
  383. void    VID_Init (unsigned char *palette)
  384. {
  385.  
  386.     int pnum, i;
  387.     XVisualInfo template;
  388.     int num_visuals;
  389.     int template_mask;
  390.     int w, h;
  391.  
  392.     int desired_width=320, desired_height=200;
  393.     
  394.     Cmd_AddCommand ("gamma", VID_Gamma_f);
  395.  
  396.     Cvar_RegisterVariable (&pixel_multiply);
  397.  
  398.     if (pipe(render_pipeline) < 0) 
  399.         Sys_Error("VID_Init: pipe");
  400.     
  401.     for (i=0 ; i<256 ; i++)
  402.         vid_gamma[i] = i;
  403.  
  404.     vid.width = 320;
  405.     vid.height = 200;
  406.     vid.aspect = 1.0;
  407.     vid.numpages = 2;
  408.     vid.colormap = host_colormap;
  409.     vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
  410.     //vid.cbits = VID_CBITS;
  411.     //vid.grades = VID_GRADES;
  412.  
  413.     srandom(getpid());
  414.  
  415.     verbose = COM_CheckParm("-verbose");
  416.     count_frames = COM_CheckParm("-count_frames");
  417.  
  418. //
  419. // open the display
  420. //
  421.     x_disp = XOpenDisplay(0);
  422.  
  423.     if (!x_disp) {
  424.         if (getenv("DISPLAY"))
  425.             Sys_Error("VID: Could not open display [%s]\n",
  426.                 getenv("DISPLAY"));
  427.         else
  428.             Sys_Error("VID: Could not open local display\n");
  429.     }
  430.  
  431.     x_screen = DefaultScreen( x_disp );
  432.     x_screen_width = WidthOfScreen( ScreenOfDisplay( x_disp, x_screen ) );
  433.     x_screen_height = HeightOfScreen( ScreenOfDisplay( x_disp, x_screen ) );
  434.  
  435.     x_center_width  = x_screen_width/2;
  436.  
  437.     x_center_height = x_screen_height/2;
  438.  
  439.     Con_Printf( "Using screen %d: %dx%d\n", x_screen, x_screen_width, x_screen_height );
  440.  
  441.     x_root_win = DefaultRootWindow( x_disp);
  442.  
  443.     //XAutoRepeatOff(x_disp);
  444.  
  445. // for debugging only
  446.     if (verbose)
  447.         XSynchronize(x_disp, True);
  448.  
  449. //
  450. // check for command-line window size
  451. //
  452.     if ((pnum=COM_CheckParm("-winsize"))) {
  453.         if (pnum >= com_argc-2)
  454.             Sys_Error("VID: -winsize <width> <height>\n");
  455.         desired_width = Q_atoi(com_argv[pnum+1]);
  456.         desired_height = Q_atoi(com_argv[pnum+2]);
  457.         if (desired_width < 1 || desired_height < 1)
  458.             Sys_Error("VID: Bad window width/height\n");        
  459.     }
  460.  
  461.     template_mask = VisualScreenMask; // make sure we get the right one    
  462.     template.screen = x_screen;
  463. //
  464. // specify a visual id
  465. //
  466.     if ((pnum=COM_CheckParm("-visualid"))) {
  467.         if (pnum >= com_argc-1)
  468.             Sys_Error("VID: -visualid <id#>\n");
  469.         template.visualid = Q_atoi(com_argv[pnum+1]);
  470.         template_mask |= VisualIDMask;
  471.     } else    {
  472.         // If not specified, find an 8 bit visual since others don't work
  473. //        template.depth = 8;
  474. //        template_mask |= VisualDepthMask;
  475.         int screen;
  476.         screen = XDefaultScreen(x_disp);
  477.         template.visualid =
  478.             XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
  479.         template_mask = VisualIDMask;
  480.     }
  481. //
  482. // pick a visual- warn if more than one was available
  483. //
  484.     x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals);
  485.     if (num_visuals > 1) {
  486.         printf("Found more than one visual id at depth %d:\n", template.depth);
  487.         for (i=0 ; i<num_visuals ; i++)
  488.             printf("    -visualid %d\n", (int)(x_visinfo[i].visualid));
  489.     }
  490.     else if (num_visuals == 0) {
  491.         if (template_mask == VisualIDMask)
  492.             Sys_Error("VID: Bad visual id %d\n", template.visualid);
  493.         else
  494.             Sys_Error("VID: No visuals at depth %d\n", template.depth);
  495.     }
  496.  
  497.     if (verbose) {
  498.         printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
  499.         printf("    screen %d\n", x_visinfo->screen);
  500.         printf("    red_mask 0x%x\n", (int)(x_visinfo->red_mask));
  501.         printf("    green_mask 0x%x\n", (int)(x_visinfo->green_mask));
  502.         printf("    blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
  503.         printf("    colormap_size %d\n", x_visinfo->colormap_size);
  504.         printf("    bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
  505.     }
  506.  
  507.     x_vis = x_visinfo->visual;
  508. //
  509. // See if we're going to do pixel multiply
  510. //
  511.     if (pixel_multiply.value < 1 || pixel_multiply.value > 4)
  512.         Cvar_SetValue("pixel_multiply", 2);
  513.     current_pixel_multiply = pixel_multiply.value;
  514.  
  515.     w = 320*current_pixel_multiply; // minimum width
  516.     h = 200*current_pixel_multiply; // minimum height
  517.     if (desired_width < w)
  518.         desired_width = w;
  519.     if (desired_height < h)
  520.         desired_height = h;
  521.  
  522.     vid.width = MP(desired_width);
  523.     vid.height = MP(desired_height);
  524.  
  525.     //
  526.     // patch things up so game doesn't fail if window is too small
  527.     //
  528.  
  529.     if (vid.width < 320) 
  530.         vid.width = 320;
  531.     if (vid.height < 200)
  532.         vid.height = 200;
  533.  
  534. //
  535. // see if we're going to use threads
  536. //
  537.     if(((sysconf(_SC_NPROCESSORS_ONLN) > 1) || COM_CheckParm("-mt")) &&  
  538.         (COM_CheckParm("-no_mt") == 0)) {
  539.         use_mt = 1;
  540.         printf("VID: Using multiple threads!\n");
  541.     }
  542.  
  543. // setup attributes for main window
  544.     {
  545.         int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
  546.         XSetWindowAttributes attribs;
  547.         Colormap tmpcmap;
  548.  
  549.         tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
  550.             x_visinfo->screen), x_vis, AllocNone);
  551.  
  552.         attribs.event_mask = x_std_event_mask;
  553.         attribs.border_pixel = 0;
  554.         attribs.colormap = tmpcmap;
  555.  
  556. // create the main window
  557.         x_win = XCreateWindow(    x_disp,
  558.             XRootWindow(x_disp, x_visinfo->screen),
  559.             0, 0,    // x, y
  560.             desired_width, desired_height,
  561.             0, // borderwidth
  562.             x_visinfo->depth,
  563.             InputOutput,
  564.             x_vis,
  565.             attribmask,
  566.             &attribs );
  567.  
  568.         if (x_visinfo->class != TrueColor)
  569.             XFreeColormap(x_disp, tmpcmap);
  570.  
  571.     }
  572.  
  573.     if (x_visinfo->depth == 8) {
  574.  
  575.     // create and upload the palette
  576.         if (x_visinfo->class == PseudoColor) {
  577.             x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
  578.             VID_SetPalette(palette);
  579.             XSetWindowColormap(x_disp, x_win, x_cmap);
  580.         }
  581.  
  582.     }
  583.  
  584.     VID_SetWindowTitle( x_win, "Quake" );
  585.  
  586. // inviso cursor
  587.     XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
  588.  
  589. // create the GC
  590.     {
  591.         XGCValues xgcvalues;
  592.         int valuemask = GCGraphicsExposures;
  593.         xgcvalues.graphics_exposures = False;
  594.         x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
  595.     }
  596.  
  597. // map the window
  598.     XMapWindow(x_disp, x_win);
  599.     XSync(x_disp, True) ;        /* wait for map */
  600. //
  601. // wait for first exposure event
  602. //
  603.     {
  604.         XEvent event;
  605.         do{
  606.             XNextEvent(x_disp, &event);
  607.             if (event.type == Expose && !event.xexpose.count)
  608.                 oktodraw = true;
  609.         } while (!oktodraw);
  610.     }
  611. //
  612. // initialize XIL
  613. //
  614.     
  615.     state = xil_open();
  616.     
  617.     if(state == NULL) {
  618.         //
  619.         //  XIL's default error handler will print an error msg on stderr
  620.         //
  621.         Sys_Error("xil_open failed\n");
  622.     }
  623.     
  624.     X11_active = true;
  625.  
  626.     VID_ResetFramebuffer();
  627.  
  628.     D_InitCaches (surfcache, sizeof(surfcache));
  629.     
  630.     vid_menudrawfn = VID_MenuDraw;
  631.     vid_menukeyfn = VID_MenuKey;
  632. }
  633.  
  634. VID_ResetFramebuffer()
  635. {
  636.     XilMemoryStorage storage;
  637.  
  638.     if (use_mt) {
  639.         VID_ResetFramebuffer_MT();
  640.         return;
  641.     }
  642.  
  643. //printf("VID_ResetFramebuffer: vid.width %d, vid.height %d\n", vid.width, vid.height);
  644.  
  645.     xil_destroy(display_image);
  646.  
  647.     xil_destroy(quake_image);
  648.  
  649.     display_image = xil_create_from_window(state, x_disp, x_win);
  650.     quake_image = xil_create(state, vid.width, vid.height, 1, XIL_BYTE);
  651.  
  652.     xil_export(quake_image);
  653.     
  654.     if (xil_get_memory_storage(quake_image, &storage) == FALSE)
  655.         Sys_Error("xil_get_memory_storage");
  656.     
  657.     xil_import(quake_image, TRUE);
  658.     xil_export(quake_image);
  659.  
  660.     if (xil_get_memory_storage(quake_image, &storage) == FALSE)
  661.         Sys_Error("xil_get_memory_storage");
  662.  
  663.     vid.rowbytes = storage.byte.scanline_stride;
  664.     vid.buffer =   storage.byte.data;
  665.     vid.conbuffer = vid.buffer;
  666.     vid.conrowbytes = vid.rowbytes;
  667.     vid.conwidth = vid.width;
  668.     vid.conheight = vid.height;
  669.     
  670.     vid.maxwarpwidth = WARP_WIDTH;
  671.     vid.maxwarpheight = WARP_HEIGHT;
  672.     vid.recalc_refdef = 1;                // force a surface cache flush
  673.  
  674.     free(d_pzbuffer);
  675.  
  676.     d_pzbuffer = malloc(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer));
  677.         //Hunk_HighAllocName(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer),"zbuff");
  678. }
  679.  
  680. VID_ResetFramebuffer_MT()
  681. {
  682.     XilMemoryStorage storage;
  683.     XilImage drain_renderpipeline();
  684.     XilImage old_display_image;
  685.  
  686.     void * update_thread();
  687.  
  688.     printf("VID_ResetFramebuffer: vid.width %d, vid.height %d\n", vid.width, vid.height);
  689.  
  690.     old_display_image = display_image;
  691.  
  692.     display_image = xil_create_from_window(state, x_disp, x_win);
  693.     
  694.     if (quake_image == NULL) 
  695.         if (thr_create(NULL, NULL, update_thread, NULL, THR_NEW_LWP, NULL) != 0)
  696.             Sys_Error("VID: thr_create");    
  697.     
  698.     quake_image = drain_renderpipeline(quake_image);
  699.  
  700.     xil_destroy(old_display_image);
  701.  
  702.     free(d_pzbuffer);
  703.  
  704.     d_pzbuffer = malloc(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer));
  705. }
  706.  
  707. void VID_ShiftPalette(unsigned char *p)
  708. {
  709.     VID_SetPalette(p);
  710. }
  711.  
  712. void VID_SetPalette(unsigned char *palette)
  713. {
  714.  
  715.     int i;
  716.     XColor colors[256];
  717.  
  718.     if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) {
  719.             if (palette != current_palette)
  720.                 memcpy(current_palette, palette, 768);
  721.             for (i=0 ; i<256 ; i++)
  722.                 {
  723.                     colors[i].pixel = i;
  724.                     colors[i].flags = DoRed|DoGreen|DoBlue;
  725.                     colors[i].red = vid_gamma[palette[i*3]] * 257;
  726.                     colors[i].green = vid_gamma[palette[i*3+1]] * 257;
  727.                     colors[i].blue = vid_gamma[palette[i*3+2]] * 257;
  728.                 }
  729.             XStoreColors(x_disp, x_cmap, colors, 256);
  730.         }
  731.  
  732. }
  733.  
  734. // Called at shutdown
  735.  
  736. void    VID_Shutdown (void)
  737. {
  738.     X11_active = false;
  739.     Con_Printf("VID_Shutdown\n");
  740.     //XAutoRepeatOn(x_disp);
  741.     xil_destroy(display_image);
  742.     xil_destroy(quake_image);
  743.     display_image = NULL;
  744.     quake_image = NULL;
  745.     XCloseDisplay(x_disp);
  746. }
  747.  
  748. int XLateKey(XKeyEvent *ev)
  749. {
  750.  
  751.     int key;
  752.     char buf[64];
  753.     KeySym keysym;
  754.  
  755.     XLookupString(ev, buf, sizeof buf, &keysym, 0);
  756.  
  757.     switch(keysym) {
  758.         case XK_Page_Up:     key = K_PGUP; break;
  759.         case XK_Page_Down:     key = K_PGDN; break;
  760.         case XK_Home:     key = K_HOME; break;
  761.         case XK_End:     key = K_END; break;
  762.         case XK_Left:     key = K_LEFTARROW; break;
  763.         case XK_Right:    key = K_RIGHTARROW;        break;
  764.         case XK_Down:     key = K_DOWNARROW; break;
  765.         case XK_Up:         key = K_UPARROW;     break;
  766.         case XK_Escape: key = K_ESCAPE;        break;
  767.         case XK_Return: key = K_ENTER;         break;
  768.         case XK_Tab:        key = K_TAB;             break;
  769.         case XK_Help:
  770.         case XK_F1:         key = K_F1;                break;
  771.         case XK_F2:         key = K_F2;                break;
  772.         case XK_F3:         key = K_F3;                break;
  773.         case XK_F4:         key = K_F4;                break;
  774.         case XK_F5:         key = K_F5;                break;
  775.         case XK_F6:         key = K_F6;                break;
  776.         case XK_F7:         key = K_F7;                break;
  777.         case XK_F8:         key = K_F8;                break;
  778.         case XK_F9:         key = K_F9;                break;
  779.         case XK_F10:        key = K_F10;             break;
  780.         case XK_F11:        key = K_F11;             break;
  781.         case XK_F12:        key = K_F12;             break;
  782.         case XK_BackSpace:
  783.         case XK_Delete: key = K_BACKSPACE; break;
  784.         case XK_Pause:    key = K_PAUSE;         break;
  785.         case XK_Shift_L:
  786.         case XK_Shift_R:        key = K_SHIFT;        break;
  787.         case XK_Control_L: 
  788.         case XK_Control_R:    key = K_CTRL;         break;
  789.         case XK_Alt_L:    
  790.         case XK_Meta_L: 
  791.         case XK_Alt_R:    
  792.         case XK_Meta_R: key = K_ALT;            break;
  793.             // various other keys on the keyboard
  794.                    case XK_F27: key = K_HOME; break;
  795.         case XK_F29: key = K_PGUP; break;
  796.         case XK_F33: key = K_END; break;
  797.         case XK_F35: key = K_PGDN; break;
  798.         case XK_Insert:
  799.         case XK_KP_Insert: key = K_INS; break;
  800.         case XK_F24: key = '-'; break;
  801.         case XK_KP_Add: key = '+'; break;
  802.         case XK_KP_Subtract: key = '-'; break;
  803.         case XK_F25: key = '/'; break;
  804.         case XK_F26: key = '*'; break;
  805.  
  806.         default:
  807.             key = (unsigned char)*buf;
  808.             break;
  809.         } 
  810.  
  811.     return key;
  812.  
  813. }
  814.  
  815. struct {
  816.     int key;
  817.     int down;
  818. } keyq[64];
  819.  
  820. int keyq_head=0;
  821. int keyq_tail=0;
  822.  
  823. int config_notify=0;
  824. int config_notify_width;
  825. int config_notify_height;
  826.  
  827. void GetEvent(void)
  828. {
  829.     XEvent x_event;
  830.     int b;
  831.  
  832.     XNextEvent(x_disp, &x_event);
  833.     switch(x_event.type) {
  834.         case KeyPress:
  835.             Key_Event(XLateKey(&x_event.xkey), true);
  836.             break;
  837.         case KeyRelease:
  838.             Key_Event(XLateKey(&x_event.xkey), false);
  839.             break;
  840.  
  841.         case MotionNotify:
  842.  
  843.             if (_windowed_mouse.value) {
  844.                 mouse_x = (float) ((int)x_event.xmotion.x - (int)(vid.width/2));
  845.                 mouse_y = (float) ((int)x_event.xmotion.y - (int)(vid.height/2));
  846.     //printf("m: x=%d,y=%d, mx=%3.2f,my=%3.2f\n", 
  847.     //    x_event.xmotion.x, x_event.xmotion.y, mouse_x, mouse_y);
  848.  
  849.                 /* move the mouse to the window center again */
  850.                 XSelectInput( x_disp, x_win, x_std_event_mask & ~PointerMotionMask );
  851.                 XWarpPointer(x_disp,None,x_win,0,0,0,0, 
  852.                     (vid.width/2),(vid.height/2));
  853.                 XSelectInput( x_disp, x_win, x_std_event_mask );
  854.             } else {
  855.                 mouse_x = (float) (x_event.xmotion.x-p_mouse_x);
  856.                 mouse_y = (float) (x_event.xmotion.y-p_mouse_y);
  857.                 p_mouse_x=x_event.xmotion.x;
  858.                 p_mouse_y=x_event.xmotion.y;
  859.             }
  860.             break;
  861.  
  862.         case ButtonPress:
  863.             b=-1;
  864.             if (x_event.xbutton.button == 1)
  865.                 b = 0;
  866.             else if (x_event.xbutton.button == 2)
  867.                 b = 2;
  868.             else if (x_event.xbutton.button == 3)
  869.                 b = 1;
  870.             if (b>=0)
  871.                 mouse_buttonstate |= 1<<b;
  872.             break;
  873.  
  874.         case ButtonRelease:
  875.             b=-1;
  876.             if (x_event.xbutton.button == 1)
  877.                 b = 0;
  878.             else if (x_event.xbutton.button == 2)
  879.                 b = 2;
  880.             else if (x_event.xbutton.button == 3)
  881.                 b = 1;
  882.             if (b>=0)
  883.                 mouse_buttonstate &= ~(1<<b);
  884.             break;
  885.         
  886.         case ConfigureNotify:
  887.             //            printf("config notify\n");
  888.             config_notify_width = x_event.xconfigure.width;
  889.             config_notify_height = x_event.xconfigure.height;
  890.             config_notify = 1;
  891.             sb_updates = 0;
  892.             break;
  893.         case Expose:    
  894.             sb_updates = 0;
  895.             break;
  896.         case ClientMessage:
  897.             if (x_event.xclient.data.l[0] == aWMDelete) Host_Quit_f();
  898.             break;
  899. #if 0
  900.         case FocusIn:
  901.             printf("FocusIn...\n");
  902.             x_focus = true;
  903.             break;
  904.         case FocusOut:
  905.             printf("FocusOut...\n");
  906.             x_focus = false;
  907.             break;
  908. #endif
  909.     }
  910.  
  911.     if (old_windowed_mouse != _windowed_mouse.value) {
  912.         old_windowed_mouse = _windowed_mouse.value;
  913.  
  914.         if (!_windowed_mouse.value) {
  915.             /* ungrab the pointer */
  916.             XUngrabPointer(x_disp,CurrentTime);
  917.         } else {
  918.             /* grab the pointer */
  919.             XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
  920.                 GrabModeAsync,x_win,None,CurrentTime);
  921.         }
  922.     }
  923. }
  924.  
  925. // flushes the given rectangles from the view buffer to the screen
  926.  
  927. void
  928. VID_Update (vrect_t *rects)
  929. {
  930.     void VID_Update_MT(vrect_t *);
  931.  
  932.  
  933.     if (count_frames) {
  934.         static int count;
  935.         static long long s;
  936.         long long gethrtime();
  937.  
  938.         if (count == 0)
  939.             s = gethrtime();
  940.  
  941.         if (count++ == 200) {
  942.             long long n = gethrtime();
  943.             count = 1;
  944.             printf("%lf frames/secs\n", 200.0/((double)(n-s) / 1e9));
  945.             s = n;
  946.         }
  947.     }
  948.  
  949.     if (use_mt) {
  950.         VID_Update_MT(rects);
  951.         return;
  952.     }
  953.  
  954.     // if the window changes dimension, skip this frame
  955.  
  956.     if (config_notify) {
  957.         int w, h;
  958.         XWindowChanges chg;
  959.         unsigned int value_mask;
  960.  
  961.         w = 320*current_pixel_multiply; // minimum width
  962.         h = 200*current_pixel_multiply; // minimum height
  963.             
  964.         if (config_notify_width < w || config_notify_height < h) {
  965.             // We must resize the window
  966.             memset(&chg, 0, sizeof(chg));
  967.             value_mask = 0;
  968.             if (config_notify_width < w) {
  969.                 config_notify_width = chg.width = w;
  970.                 value_mask |= CWWidth;
  971.             }
  972.             if (config_notify_height < h) {
  973.                 config_notify_height = chg.height = h;
  974.                 value_mask |= CWHeight;
  975.             }
  976.             if (value_mask)
  977.                 XConfigureWindow(x_disp, x_win, value_mask, &chg);
  978.         }
  979.  
  980.         config_notify = 0;
  981.  
  982.         vid.width = MP(config_notify_width) & ~3;
  983.         vid.height = MP(config_notify_height);
  984.  
  985.         if (vid.width < 320) 
  986.             vid.width = 320;
  987.         if (vid.height < 200)
  988.             vid.height = 200;
  989.         
  990.         VID_ResetFramebuffer();
  991.  
  992.         return;
  993.     }
  994.     // if pixel multiply changed, skip this frame
  995.     if (CheckPixelMultiply())
  996.         return;
  997.  
  998.     while (rects) { // I've never seen more than one rect?
  999.         XilMemoryStorage storage;
  1000.  
  1001.         xil_import(quake_image, TRUE); // let xil control the image
  1002.  
  1003.         if (current_pixel_multiply < 2)
  1004.             xil_copy(quake_image, display_image);
  1005.         else
  1006.             xil_scale(quake_image, display_image, "nearest",
  1007.                   (float)current_pixel_multiply, (float)current_pixel_multiply);
  1008.  
  1009.         xil_export(quake_image);  // back to quake
  1010.  
  1011.         if (xil_get_memory_storage(quake_image, &storage) == FALSE)
  1012.             Sys_Error("xil_get_memory_storage");
  1013.  
  1014.         vid.buffer =   storage.byte.data;
  1015.         vid.conbuffer = vid.buffer;
  1016.  
  1017.         rects = rects->pnext;
  1018.     }
  1019. }
  1020.  
  1021. void
  1022. VID_Update_MT (vrect_t *rects)
  1023. {
  1024.     XilImage sched_update();
  1025.  
  1026.     // if the window changes dimension, skip this frame
  1027.  
  1028.     if (config_notify) {
  1029.         int w, h;
  1030.         XWindowChanges chg;
  1031.         unsigned int value_mask;
  1032.  
  1033.         w = 320*current_pixel_multiply; // minimum width
  1034.         h = 200*current_pixel_multiply; // minimum height
  1035.             
  1036.         if (config_notify_width < w || config_notify_height < h) {
  1037.             // We must resize the window
  1038.             memset(&chg, 0, sizeof(chg));
  1039.             value_mask = 0;
  1040.             if (config_notify_width < w) {
  1041.                 config_notify_width = chg.width = w;
  1042.                 value_mask |= CWWidth;
  1043.             }
  1044.             if (config_notify_height < h) {
  1045.                 config_notify_height = chg.height = h;
  1046.                 value_mask |= CWHeight;
  1047.             }
  1048.             if (value_mask)
  1049.                 XConfigureWindow(x_disp, x_win, value_mask, &chg);
  1050.         }
  1051.  
  1052.         config_notify = 0;
  1053.  
  1054.         vid.width = MP(config_notify_width) & ~3;
  1055.         vid.height = MP(config_notify_height);
  1056.  
  1057.         if (vid.width < 320) 
  1058.             vid.width = 320;
  1059.         if (vid.height < 200)
  1060.             vid.height = 200;
  1061.         
  1062.         VID_ResetFramebuffer_MT();
  1063.  
  1064.         return;
  1065.     }
  1066.     // if pixel multiply changed, skip this frame
  1067.     if (CheckPixelMultiply())
  1068.         return;
  1069.  
  1070.     quake_image = sched_update(quake_image);
  1071. }
  1072.  
  1073. XilImage
  1074. drain_renderpipeline(XilImage old)
  1075. {
  1076.     XilImage new;
  1077.  
  1078.     XilMemoryStorage storage;
  1079.     
  1080.     if (old) 
  1081.         if (read(render_pipeline[1], &new, sizeof(new)) != sizeof (new)) {
  1082.             Sys_Error("drain_renderpipeline: read");
  1083.             xil_destroy(new);
  1084.         }
  1085.  
  1086.     xil_destroy(old);
  1087.  
  1088.  
  1089.     new = xil_create(state, vid.width, vid.height, 1, XIL_BYTE);
  1090.     
  1091.     if (write(render_pipeline[0], &new, sizeof (new)) != sizeof(new)) 
  1092.         Sys_Error("drain_renderpipeline: write");
  1093.  
  1094.     new = xil_create(state, vid.width, vid.height, 1, XIL_BYTE);
  1095.  
  1096.     xil_export(new);
  1097.  
  1098.     if (xil_get_memory_storage(new, &storage) == FALSE)
  1099.         Sys_Error("xil_get_memory_storage");
  1100.  
  1101.     vid.rowbytes = storage.byte.scanline_stride;
  1102.     vid.buffer =   storage.byte.data;
  1103.     vid.conbuffer = vid.buffer;
  1104.     vid.conrowbytes = vid.rowbytes;
  1105.     vid.conwidth = vid.width;
  1106.     vid.conheight = vid.height;
  1107.     
  1108.     vid.maxwarpwidth = WARP_WIDTH;
  1109.     vid.maxwarpheight = WARP_HEIGHT;
  1110.     vid.recalc_refdef = 1;                // force a surface cache flush
  1111.  
  1112.     return(new);
  1113.  
  1114. }
  1115.  
  1116. XilImage
  1117. sched_update(XilImage image)
  1118. {
  1119.     XilImage new;
  1120.     XilMemoryStorage storage;
  1121.  
  1122.     if (write(render_pipeline[1], &image, sizeof(image)) != sizeof (image)) 
  1123.         Sys_Error("sched_update:write");
  1124.  
  1125.     if (read(render_pipeline[1], &new, sizeof(new)) != sizeof (new))
  1126.         Sys_Error("sched_update:read");
  1127.  
  1128.     xil_export(new);
  1129.  
  1130.     if (xil_get_memory_storage(new, &storage) == FALSE)
  1131.         Sys_Error("xil_get_memory_storage");
  1132.  
  1133.     vid.buffer =   storage.byte.data;
  1134.     vid.conbuffer = vid.buffer;
  1135.  
  1136.     return (new);
  1137. }
  1138.  
  1139. void *update_thread()
  1140. {
  1141.     XilImage image;
  1142.  
  1143.     if (!X11_active)
  1144.         return;
  1145.  
  1146.     while (read(render_pipeline[0], &image, sizeof (image)) == sizeof(image)) {
  1147.  
  1148.         xil_import(image, TRUE); // let xil control the image
  1149.  
  1150.         if (!display_image)
  1151.             return;
  1152.  
  1153.         if (current_pixel_multiply < 2)
  1154.             xil_copy(image, display_image);
  1155.         else
  1156.             xil_scale(image, display_image, "nearest",
  1157.                   (float)current_pixel_multiply, (float)current_pixel_multiply);
  1158.  
  1159.         if (write(render_pipeline[0], &image, sizeof (image)) != sizeof(image)) 
  1160.             Sys_Error("update_thread: write");
  1161.     }
  1162. }
  1163.  
  1164.  
  1165. static int dither;
  1166.  
  1167. void VID_DitherOn(void)
  1168. {
  1169.     if (dither == 0) {
  1170.         vid.recalc_refdef = 1;
  1171.         dither = 1;
  1172.     }
  1173. }
  1174.  
  1175. void VID_DitherOff(void)
  1176. {
  1177.     if (dither) {
  1178.         vid.recalc_refdef = 1;
  1179.         dither = 0;
  1180.     }
  1181. }
  1182.  
  1183. void VID_SetDefaultMode( void )
  1184. {
  1185. }
  1186.  
  1187. int I_OpenWindow(void)
  1188. {
  1189.     return 0;
  1190. }
  1191.  
  1192. void I_EraseWindow(int window)
  1193. {
  1194.  
  1195. }
  1196.  
  1197. void I_DrawCircle(int window, int x, int y, int r)
  1198. {
  1199. }
  1200.  
  1201. void I_DisplayWindow(int window)
  1202. {
  1203. }
  1204.  
  1205. void Sys_SendKeyEvents(void)
  1206. {
  1207.     // get events from x server
  1208.            if (x_disp) {
  1209.                    while (XPending(x_disp)) GetEvent();
  1210.                    while (keyq_head != keyq_tail) {
  1211.                            Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down);
  1212.                            keyq_tail = (keyq_tail + 1) & 63;
  1213.                        }
  1214.                }
  1215. }
  1216.  
  1217. void IN_Init (void)
  1218. {
  1219.     Cvar_RegisterVariable (&_windowed_mouse);
  1220.     Cvar_RegisterVariable (&m_filter);
  1221.    if ( COM_CheckParm ("-nomouse") )
  1222.      return;
  1223.    mouse_x = mouse_y = 0.0;
  1224.    mouse_avail = 1;
  1225. }
  1226.  
  1227. void IN_Shutdown (void)
  1228. {
  1229.    mouse_avail = 0;
  1230. }
  1231.  
  1232. void IN_Commands (void)
  1233. {
  1234.     int i;
  1235.    
  1236.     if (!mouse_avail) return;
  1237.    
  1238.     for (i=0 ; i<mouse_buttons ; i++) {
  1239.         if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
  1240.             Key_Event (K_MOUSE1 + i, true);
  1241.  
  1242.         if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
  1243.             Key_Event (K_MOUSE1 + i, false);
  1244.     }
  1245.     mouse_oldbuttonstate = mouse_buttonstate;
  1246. }
  1247.  
  1248. void IN_Move (usercmd_t *cmd)
  1249. {
  1250.     if (!mouse_avail)
  1251.         return;
  1252.    
  1253.     if (m_filter.value) {
  1254.         mouse_x = (mouse_x + old_mouse_x) * 0.5;
  1255.         mouse_y = (mouse_y + old_mouse_y) * 0.5;
  1256.     }
  1257.  
  1258.     old_mouse_x = mouse_x;
  1259.     old_mouse_y = mouse_y;
  1260.    
  1261.     mouse_x *= sensitivity.value;
  1262.     mouse_y *= sensitivity.value;
  1263.    
  1264.     if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
  1265.         cmd->sidemove += m_side.value * mouse_x;
  1266.     else
  1267.         cl.viewangles[YAW] -= m_yaw.value * mouse_x;
  1268.     if (in_mlook.state & 1)
  1269.         V_StopPitchDrift ();
  1270.    
  1271.     if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) {
  1272.         cl.viewangles[PITCH] += m_pitch.value * mouse_y;
  1273.         if (cl.viewangles[PITCH] > 80)
  1274.             cl.viewangles[PITCH] = 80;
  1275.         if (cl.viewangles[PITCH] < -70)
  1276.             cl.viewangles[PITCH] = -70;
  1277.     } else {
  1278.         if ((in_strafe.state & 1) && noclip_anglehack)
  1279.             cmd->upmove -= m_forward.value * mouse_y;
  1280.         else
  1281.             cmd->forwardmove -= m_forward.value * mouse_y;
  1282.     }
  1283.     mouse_x = mouse_y = 0.0;
  1284. }
  1285.  
  1286. //void VID_UnlockBuffer(void) { }
  1287. //void VID_LockBuffer(void) { }
  1288.  
  1289.